package inutan.game.service;

import inutan.common.constant.DataConstant;
import inutan.common.context.FlowContext;
import inutan.common.message.ActionErrorEnum;
import inutan.data.Mission.MissionVal;
import inutan.data.Mission.TargetType;
import inutan.data.MissionGroup.GroupType;
import inutan.game.business.GameFlowContext;
import inutan.game.entity.*;
import inutan.game.entity.prop.BaseItemInfo;
import inutan.game.proto.TaskProto;
import inutan.game.task.TaskStatus;
import inutan.game.storage.StorageContext;
import luban.common.Command;
import luban.task.ResTaskInfo;
import luban.task.TaskInfo;
import org.ricks.common.exception.MsgException;
import org.ricks.common.utils.DateUtils;
import org.ricks.ioc.anno.Autowired;
import org.ricks.ioc.anno.Bean;
import org.ricks.orm.OrmContext;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

@Bean
public class TaskService {

    @Autowired
    private AchievementService achievementService;

    /**
     * @Explain --> 获取所有主线 / 支线任务数据
     * @Author yanwang
     * @Date 2023/4/4 16:22
     **/
    public ResTaskInfo getTaskList(long userId) {
        Optional<MainlineTask> mainTask = OrmContext.me().uniqueCacheLoad(MainlineTask.class,userId);
        List<Task> sideTask = OrmContext.me().multiCacheLoad(Task.class,userId);
        return TaskProto.getTaskInfo(mainTask, sideTask);
    }

    /**
     * @Explain --> 接取任务 策划说客户端没有玩家主动接取任务功能
     * @Author yanwang
     * @Date 2023/4/3 16:28
     **/
    public Optional<TaskInfo> acceptTask(long userId, MissionVal missionData) {
        Optional<TaskInfo> info = Optional.empty();
        //获得task配置信息
        switch (missionData.missiontype) {
            case GroupType.MainMission:
                Optional<MainlineTask> mainlineTask = acceptMainTask(userId, missionData);
                info = mainlineTask.isPresent() ? Optional.of(TaskProto.taskInfo(mainlineTask.get())) : info;
                break;
            case GroupType.AchieveMission:
                Optional<Achievement> achievement = achievementService.acceptTask(userId, missionData);
                info = achievement.isPresent() ? Optional.of(TaskProto.taskInfo(achievement.get())) : info;
                break;
            case GroupType.RatingMission:
                Optional<Task> task = openSideMission(userId, missionData);
                info = task.isPresent() ? Optional.of(TaskProto.taskInfo(task.get())) : info;
                break;
        }
        return info;
    }
    /**
     * @Explain --> 根据任务类型 获得基础进度
     * @Author yanwang
     * @Date 2023/4/3 16:48
     **/
    public Map<Integer, Integer> getProgress(long userId, MissionVal missionData) {
        Map<Integer, Integer> progress = new HashMap<>();
        progress.put(missionData.targetType, 0);
        switch (missionData.targetType) {
            case TargetType.MissionTargetType015:
                OrmContext.me().uniqueCacheLoad(UserInfo.class,userId).ifPresent(user -> {
                    progress.replace(missionData.targetType, user.getLevel());
                });
                break;
        }
        return progress;
    }


    /**
    * @Explain --> 更新任务进度
    * @Author yanwang
    * @Date 2023/5/19 13:41
    **/
    public void doTask(GameFlowContext context, int targetType, Predicate<MissionVal> targetBool, TaskNumFunction<MissionVal> numFuntion, boolean isAdd) {
        doMainTask(context,targetType,targetBool,numFuntion,isAdd);
        doSideTask(context,targetType,targetBool,numFuntion,isAdd);
        achievementService.doAchievement(context,targetType,targetBool,numFuntion,isAdd);
    }


    /**
     * @Explain --> 接取下一个任务
     * @Author yanwang
     * @Date 2023/4/3 16:32
     **/
    public List<TaskInfo> doNextTask(int taskId, long userId) {
        //获得当前任务的 所有下一个 前置任务都已完成 的任务信息
        List<MissionVal> nextMission = StorageContext.tables().getTbMission().getDataList().stream().filter(x -> x.activeCfgPremissions.contains(taskId) && verifyPreTask(x, userId)).collect(Collectors.toList());
        //循环解锁 接取下一个任务
        List<TaskInfo> newTaskList = new ArrayList<>();
        nextMission.forEach(mission -> acceptTask(userId, mission).ifPresent(x -> newTaskList.add(x)));
        return newTaskList;
    }

    /**
     * @Explain --> 完成任务
     * @Author yanwang
     * @Date 2023/4/3 16:33
     **/
    public void completeTask(GameFlowContext context, int taskId) {
        MissionVal data  =StorageContext.tables().getTbMission().getDataMap().get(taskId);
        ActionErrorEnum.dataNotExist.assertNonNull(data);
        ActionErrorEnum.taskCanNotComplete.assertFalse(data.targetType == TargetType.MissionTargetType999);//999类型任务 不能完成
        long userId = context.getUserId();
        switch (data.missiontype) {
            case GroupType.MainMission:
                OrmContext.me().uniqueCacheLoad(MainlineTask.class,userId).ifPresentOrElse(x -> {
                    ActionErrorEnum.taskNotComplete.assertTrue(x.getState() == TaskStatus.CanComplete);//任务未完成
                    completeMainTask(context, x, data);
                }, () -> {
                    throw new MsgException(ActionErrorEnum.taskNotExist);//任务不存在
                });
                break;
            case GroupType.AchieveMission:
                achievementService.completeTask(context, data); //完成成就
                break;
            case GroupType.RatingMission:
                Optional.of(OrmContext.me().multiCacheGet(Task.class,userId, x -> x.getTaskId() == taskId)).ifPresentOrElse(x -> {
                    ActionErrorEnum.taskNotComplete.assertTrue(x.getState() == TaskStatus.CanComplete);//任务未完成
                    completeSideTask(context, x, data);
                }, () -> {
                    throw new MsgException(ActionErrorEnum.taskNotExist);//任务不存在
                });
                break;
        }
    }

    /**
     * @Explain --> 前置任务校验
     * @Author yanwang
     * @Date 2023/3/29 11:26
     **/
    public boolean verifyPreTask(MissionVal missionData, long userId) {
        boolean noVerify = missionData.activeCfgPremissions.stream().allMatch(x -> x == 0);
        switch (missionData.missiontype) {
            case GroupType.AchieveMission:
                //成就前置任务 不在FinishTask表中
                return noVerify || achievementService.verifyAchieveComplete(missionData.activeCfgPremissions, userId);
            default:
                 return noVerify || OrmContext.me().uniqueCacheLoad(UserConstant.class,userId).get().getFinishTaskId().containsAll(missionData.activeCfgPremissions);
        }
    }

    /**
     * @Explain --> 玩家等级校验
     * @Author yanwang
     * @Date 2023/3/29 11:28
     **/
    public boolean verifyRoleLevel(MissionVal missionData, long userId) {
        Optional<UserInfo> user = OrmContext.me().uniqueCacheLoad(UserInfo.class,userId);
        if (user.isPresent()) {
            return user.get().getLevel() >= missionData.activeCfgPlayerlv;
        }
        return false;
    }

    /**
     * @Explain --> 初始化主线任务 支线任务
     * @Author yanwang
     * @Date 2023/3/29 17:36
     **/
    public void initFirstMission(long userId) {
        List<MissionVal> missionList = StorageContext.tables().getTbMission().getDataList().stream().filter(x -> x.activeCfgPremissions.stream().allMatch(n -> n == 0)).collect(Collectors.toList());
        missionList.forEach(mission -> acceptTask(userId, mission));
    }

    interface TaskNumFunction<T> {
        int getNum(T t);
    }

    /**
    * @Explain --> 玩家升级事件
    * @Author yanwang
    * @Date 2023/5/19 13:43
    **/
    public void monitorRoleLevelUp(GameFlowContext context, int lv, int oldLv) {
        doTask(context, TargetType.MissionTargetType015, x -> true, missionVal -> lv, false);
        //获取等级已经达到的任务 判断是否可以接取
        /*List<MissionVal> missionVals = getDataListFilter(MissionVal.class,x->oldLv > x.activeCfgPlayerlv && x.activeCfgPlayerlv <= lv);
        missionVals.forEach(data->{
            if(verifyPreTask(data,context.getUserId()))
                acceptTask(context.getUserId(),data);
        });*/
        //获取玩家所有Unopened任务 判断等级是否达到
        List<Integer> taskIds = OrmContext.me().multiCacheLoadAll(MainlineTask.class,context.getUserId() , x -> x.getState() == TaskStatus.Unopened).stream().map(x -> x.getTaskId()).collect(Collectors.toList());
        taskIds.addAll(OrmContext.me().multiCacheLoadAll(Task.class,context.getUserId(),x -> x.getState() == TaskStatus.Unopened).stream().map(x -> x.getTaskId()).collect(Collectors.toList()));
        StorageContext.tables().getTbMission().getDataList().stream().filter( x -> taskIds.contains(x.id)).forEach(data -> {
            acceptTask(context.getUserId(), data);
        });
    }

    /**
    * @Explain -->在场景中放置道具事件
    * @Author yanwang
    * @Date 2023/5/19 13:43
    **/
    public void monitorChangeFurniture(GameFlowContext context, int furnitureId, int num) {
        doTask(context, TargetType.MissionTargetType024, x -> x.targetCfg1 == furnitureId, missionVal -> num, false);
    }

    /**
    * @Explain --> 完成订单事件
    * @Author yanwang
    * @Date 2023/5/19 13:44
    **/
    public void monitorSubOrder(GameFlowContext context) {
        doTask(context, TargetType.MissionTargetType004, x -> true, missionVal -> 1, true);
    }

    /**
    * @Explain --> 增加道具事件
    * @Author yanwang
    * @Date 2023/5/19 13:44
    **/
    public void monitorAddItem(GameFlowContext context, List<BaseItemInfo> itemInfos) {
        TaskNumFunction<MissionVal> getNum = missionVal -> {
            int count = itemInfos.stream().filter(x -> missionVal.targetCfg1 == x.getItemId()).mapToInt(x -> x.getCount()).sum();
            return count;
        };
        doTask(context, TargetType.MissionTargetType025, x -> itemInfos.stream().anyMatch(n -> n.getItemId() == x.targetCfg1), getNum, true);
    }

    public void monitor13(GameFlowContext context,int num){
        doTask(context,TargetType.MissionTargetType013,x->true,n->num,true);
    }
    public void monitor998(GameFlowContext context){
        doTask(context,TargetType.MissionTargetType998,x->true,x->1,false);
    }

    /**
     * @Explain --> 开启主线任务 主线任务每个玩家只有一条数据
     * @Author yanwang
     * @Date 2023/4/3 16:29
     **/
    private Optional<MainlineTask> acceptMainTask(long userId, MissionVal missionData) {
        Optional<MainlineTask> mainlineTask = OrmContext.me().uniqueCacheLoad(MainlineTask.class,userId);
        if (!mainlineTask.isPresent()) {
            MainlineTask task = new MainlineTask();
            task.setId(userId);
            task.setTaskId(missionData.id);
            task.setState(verifyRoleLevel(missionData, userId) ? TaskStatus.Accept : TaskStatus.Unopened);//也是需要校验玩家等级的 等级不满足 则Unopened？ 玩家每一次升级都需要判断Unopened
            task.setProgress(getProgress(userId, missionData));
            OrmContext.me().insert(task);
            return Optional.of(task);
        } else {
            //主线任务已存在 判断是任务是否开启  未开启且等级已达到 则开启主线任务
            MainlineTask task = mainlineTask.get();
            MissionVal data = StorageContext.tables().getTbMission().get( task.getTaskId());
            if (task.getState() == TaskStatus.Unopened && verifyRoleLevel(data, userId)) {
                task.setState(TaskStatus.Accept);
                OrmContext.me().update(task);
                return Optional.of(task);
            }
            return Optional.empty();
        }
    }

    /**
     * @Explain --> 开启支线任务
     * @Author yanwang
     * @Date 2023/4/3 16:28
     **/
    public Optional<Task> openSideMission(long userId, MissionVal missionData) {
        //判断支线任务是否存在
        List<Task> newTaskList = new ArrayList<>();
        Optional<Task> task = Optional.of(OrmContext.me().multiCacheGet(Task.class, userId, x -> x.getTaskId() == missionData.id));
        task.ifPresentOrElse(x -> {
            //不存在则新增  且状态为Unopened  则修改状态
            if (x.getState() == TaskStatus.Unopened && verifyRoleLevel(missionData, userId)) {
                x.setState(TaskStatus.Accept);
                OrmContext.me().update(x);
                newTaskList.add(x);
            }
        }, () -> {
            //存在判断状态且等级满足 等级满足则 CanAccept 不满足则Unopened
            int status = verifyRoleLevel(missionData, userId) ? TaskStatus.Accept : TaskStatus.Unopened;
            Task vo = new Task();
            vo.setTaskId(missionData.id);
            vo.setRoleId(userId);
            vo.setTaskType(missionData.missiontype);
            vo.setState(status);
            vo.setProgress(getProgress(userId, missionData));
            vo.setCreateTime(DateUtils.current());
            OrmContext.me().insert(vo);
            if (status == TaskStatus.Accept) newTaskList.add(vo);
        });
        return newTaskList.stream().findFirst();
    }

    /**
    * @Explain --> 更新主线任务进度
    * @Author yanwang
    * @Date 2023/5/19 13:45
    **/
    public void doMainTask(GameFlowContext context, int targetType, Predicate<MissionVal> targetBool, TaskNumFunction<MissionVal> numFuntion, boolean isAdd){
        long userId = context.getUserId();
        Optional<MainlineTask> mainTasks = OrmContext.me().uniqueCacheLoad(MainlineTask.class,userId);
        Optional<MainlineTask> mainTask = mainTasks.filter(x -> x.getProgress().containsKey(targetType) && x.getState() == TaskStatus.Accept);
        mainTask.ifPresent(x -> {

            MissionVal val = StorageContext.tables().getTbMission().get(x.getTaskId());
            if (val != null) {
                if (targetBool.test(val)) {
                    int num = numFuntion.getNum(val);
                    int count = isAdd ? x.getProgress().get(targetType) + num : num;
                    x.getProgress().replace(targetType, count);
                    if (count >= val.numCount) x.setState(TaskStatus.CanComplete);
                    if (count >= val.numCount && !val.ifCheck) completeMainTask(context, x, val);
                    else
                        context.sendResponse(DataConstant.BROADCAST_MESSAGE, Command.UpdateTask, TaskProto.taskInfo(x));
                    OrmContext.me().update(x);
                }
            }
        });
    }

    /**
    * @Explain --> 更新支线任务进度
    * @Author yanwang
    * @Date 2023/5/19 13:46
    **/
    public void doSideTask(GameFlowContext context, int targetType, Predicate<MissionVal> targetBool, TaskNumFunction<MissionVal> numFuntion, boolean isAdd){
        long userId = context.getUserId();
        List<Task> taskList = OrmContext.me().multiCacheLoadAll(Task.class,userId, x -> x.getProgress().containsKey(targetType) && x.getState() == TaskStatus.Accept);
        List<Task> taskResult = taskList.stream().map(x -> {
            MissionVal val = StorageContext.tables().getTbMission().getDataMap().get(x.getTaskId());
            if (val != null) {
                if (targetBool.test(val)) {
                    int num = numFuntion.getNum(val);
                    int count = isAdd ? x.getProgress().get(targetType) + num : num;
                    x.getProgress().replace(targetType, count);
                    if (count >= val.numCount) x.setState(TaskStatus.CanComplete);
                    if (count >= val.numCount && !val.ifCheck) completeSideTask(context, x, val);
                    else
                        context.sendResponse(DataConstant.BROADCAST_MESSAGE, Command.UpdateTask, TaskProto.taskInfo(x));
                    return x;
                }
            }
            return null;
        }).collect(Collectors.toList());
        taskResult.forEach(t -> OrmContext.me().update(t));
    }

    /**
     * @Explain --> 完成主线任务 记录数据
     * @Author yanwang
     * @Date 2023/4/3 16:33
     **/
    private void completeMainTask(GameFlowContext context, MainlineTask taskVo, MissionVal data) {
        OrmContext.me().delete(taskVo);
        saveFinishTask(context, taskVo.getTaskId(), data);
    }

    /**
     * @Explain --> 完成支线任务 记录数据
     * @Author yanwang
     * @Date 2023/4/3 16:33
     **/
    private void completeSideTask(GameFlowContext context, Task taskVo, MissionVal data) {
        OrmContext.me().delete(taskVo);
        saveFinishTask(context, taskVo.getTaskId(), data);
    }

    /**
     * @Explain --> 保存已完成任务数据  接取下一个任务
     * @Author yanwang
     * @Date 2023/4/3 16:33
     **/
    private void saveFinishTask(GameFlowContext context, int taskId, MissionVal data) {
        long userId = context.getUserId();
        //发放完成任务奖励
        context.addProps(context.addPropByReward(data.reward));
        //保存 任务完成记录
        saveFinishTask(userId,taskId);
        //解锁/接取下一个任务
        //EventBus.get().publish(new CompleteTaskEvent(userId, taskId));
        List<TaskInfo> newTaskList = doNextTask(taskId, userId);
        context.sendResponse(DataConstant.BROADCAST_MESSAGE, Command.CompleteTasks, TaskProto.getCompleteTask(taskId, newTaskList));
    }

    public void saveFinishTask(long userId,int taskId){
        UserConstant userConstant = OrmContext.me().uniqueCacheLoad(UserConstant.class,userId).get();
        if(!userConstant.getFinishTaskId().contains(taskId)){
            userConstant.getFinishTaskId().add(taskId);
            OrmContext.me().update(userConstant);
        }
    }

    /**
     * @Explain --> 补充任务数据（暂时不用）
     * @Author yanwang
     * @Date 2023/4/4 16:57
     **/
    private void appendNewTask(long userId) {
        //判断没有接取的任务中 是否存在前置任务已完成 但没有接取的任务
        List<Integer> finishTaskIds = OrmContext.me().uniqueCacheLoad(UserConstant.class,userId).get().getFinishTaskId();
        List<Integer> sideTaskIds = OrmContext.me().multiCacheLoad(Task.class,userId).stream().map(x -> x.getTaskId()).collect(Collectors.toList());
        Optional<MainlineTask> mainlineTask = OrmContext.me().uniqueCacheLoad(MainlineTask.class,userId);
        int mainTaskId = mainlineTask.isPresent() ? mainlineTask.get().getTaskId() : 0;

        List<MissionVal> missionList = StorageContext.tables().getTbMission().getDataList().stream().filter( x -> !finishTaskIds.contains(x.id)).collect(Collectors.toList());
        missionList.stream().filter(x -> !sideTaskIds.contains(x.id) && mainTaskId != x.id).forEach(data -> {
            if (finishTaskIds.containsAll(data.activeCfgPremissions) && verifyRoleLevel(data, userId)) {
                acceptTask(userId, data);
            }
        });
    }

}
